/* eslint-disable @typescript-eslint/no-var-requires */

const { createProxyMiddleware } = require("http-proxy-middleware");
const axios = require("axios");
const { Agent } = require("https");

module.exports = function (app) {
    const { DEBUG_ORIGIN = `https://127.0.0.1` } = process.env;
    const ORIGIN = `http://localhost:4017`;
    const REDIRECT_URI = `${ORIGIN}/anyshare/oauth2/login/callback`;
    const POST_LOGOUT_REDIRECT_URI = `${ORIGIN}/anyshare/oauth2/logout/callback`;

    const registerClientPromise = axios
        .post(
            "/oauth2/clients",
            {
                grant_types: ["authorization_code", "refresh_token", "implicit"],
                scope: "offline openid all",
                redirect_uris: [REDIRECT_URI],
                post_logout_redirect_uris: [POST_LOGOUT_REDIRECT_URI],
                client_name: "WebDebugClient",
                metadata: {
                    device: {
                        name: "WebDebugClient",
                        client_type: "unknown",
                        description: `WebDebugClient`,
                    },
                },
                response_types: ["token id_token", "code", "token"],
            },
            {
                baseURL: DEBUG_ORIGIN,
                httpsAgent: new Agent({
                    rejectUnauthorized: false,
                }),
            }
        )
        .then(({ data }) => data);

    app.use(
        "/api",
        createProxyMiddleware({
            secure: false,
            target: `${DEBUG_ORIGIN}/api/`,
            pathRewrite: { "^/api": "/" },
            changeOrigin: true,
            rejectUnauthorized: false,
        })
    );

    app.use(
        "/anyshare/oauth2/login/refreshToken",
        createProxyMiddleware({
            secure: false,
            target: `${DEBUG_ORIGIN}/anyshare/oauth2/login/refreshToken`,
            pathRewrite: { "^/anyshare/oauth2/login/refreshToken": "/" },
            changeOrigin: true,
            rejectUnauthorized: false,
        })
    );

    app.use(
        "/link",
        createProxyMiddleware({
            secure: false,
            target: `${DEBUG_ORIGIN}/link/`,
            pathRewrite: { "^/link": "/" },
            changeOrigin: true,
            rejectUnauthorized: false,
        })
    );

    app.use(
        "/static",
        createProxyMiddleware({
            target: `${DEBUG_ORIGIN}/static`,
            pathRewrite: { "^/static": "/" },
            changeOrigin: true,
            secure: false,
        })
    );

    app.get("/anyshare/oauth2/login", async function (req, res) {
        const { client_id } = await registerClientPromise;
        const { redirect, lang } = req.query;
        const state = Buffer.from(decodeURIComponent(redirect)).toString("base64");
        res.cookie("state", state, { httpOnly: true });
        const url = `${DEBUG_ORIGIN}/oauth2/auth?client_id=${client_id}&response_type=code&scope=offline+openid+all&redirect_uri=${encodeURIComponent(
            REDIRECT_URI
        )}&state=${encodeURIComponent(state)}&lang=${lang}`;

        res.redirect(url);
    });

    app.get("/anyshare/oauth2/login/callback", async function (req, res) {
        const { client_secret, client_id } = await registerClientPromise;
        const { code, state } = req.query;
        const params = new URLSearchParams();

        params.append("grant_type", "authorization_code");
        params.append("code", code);
        params.append("redirect_uri", REDIRECT_URI);

        const {
            data: { access_token, id_token },
        } = await axios.post(`${DEBUG_ORIGIN}/oauth2/token`, params, {
            headers: {
                "Content-Type": "application/x-www-form-urlencoded",
                Authorization: `Basic ${Buffer.from(
                    `${encodeURIComponent(client_id)}:${encodeURIComponent(client_secret)}`
                ).toString("base64")}`,
            },
            httpsAgent: new Agent({
                rejectUnauthorized: false,
            }),
        });
        res.cookie("client.oauth2_token", access_token, { httpOnly: false });
        res.cookie("id_token", id_token, { httpOnly: false });
        res.clearCookie("state");
        res.redirect(Buffer.from(decodeURIComponent(state), "base64").toString());
    });

    app.get("/anyshare/oauth2/logout", async function (req, res) {
        const { redirect } = req.query;
        const { id_token } = req.cookies || {};
        if (id_token) {
            const state = Buffer.from(decodeURIComponent(redirect)).toString("base64");
            res.cookie("state", state, { httpOnly: true });
            res.redirect(
                `${DEBUG_ORIGIN}/oauth2/session/logout?id_token_hint=${id_token}&post_logout_redirect_uri=${POST_LOGOUT_REDIRECT_URI}&state=${state}`
            );
        } else {
            res.clearCookie("client.oauth2_token");
            res.clearCookie("id_token");
            res.clearCookie("state");
            res.redirect(redirect);
        }
    });

    app.get("/anyshare/oauth2/logout/callback", async function () {
        const { state } = req.query;
        const { state: cookieState } = req.cookies;
        const token = req.cookies[`client.oauth2_token`];
        const { client_secret, client_id } = await registerClientPromise;
        if (state === cookieState) {
            const revokeTokenUri = new URL("oauth2/revoke", this.hydraUriBase);
            if (token) {
                try {
                    const params = new URLSearchParams();
                    params.append("token", token);
                    await axios.post(`${DEBUG_ORIGIN}/oauth2/revode`, params, {
                        headers: {
                            "Content-Type": "application/x-www-form-urlencoded",
                            Authorization: `Basic ${Buffer.from(
                                `${encodeURIComponent(client_id)}:${encodeURIComponent(client_secret)}`
                            ).toString("base64")}`,
                        },
                        httpsAgent: new Agent({
                            rejectUnauthorized: false,
                        }),
                    });
                } catch (e) {
                    const { status, data } = e.response;
                    res.statusCode = status;
                    res.json({
                        code: status,
                        ...data,
                    });
                }
                res.clearCookie("state");
                res.clearCookie("client.oauth2_token");
                res.clearCookie("id_token");
            }
            res.redirect(Buffer.from(decodeURIComponent(state), "base64").toString());
        } else {
            res.statusCode = 400;
            res.json({
                code: 400,
                cause: "state参数不一致",
                message: "state参数不一致",
            });
        }
    });
};
